#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include "file.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define size 1024
#define MAX_AREA 64
#define SEP " "

char* argv[MAX_AREA];
char* filename;
int exitcode = 0;


const char* CurrentWorkDir() 
{
    char* pwd = getenv("PWD");
    if(pwd) return pwd;
    else  return "none";
}


const char* UserName()
{
    char* username = getenv("USER");
    if(username) return username;
    else return "none";
}

const char* HostName()
{
    char* hostname = getenv("HOSTNAME");
    if(hostname) return hostname;
    else return "none";
}

const char* HOME()
{
    char* home = getenv("HOME");
    if(home) return home;
    else return "none";
}

int interactive(char out[])
{
    printf("[%s@%s %s]$",UserName(),HostName(),CurrentWorkDir());
    fgets(out,size,stdin);
    out[strlen(out)-1] = 0;//这里fgets会读取'\n',需要把数组最后一位置'\0'
    return strlen(out);

}

//得到文件名
void GetFileName(char in[], int i)
{
    while(in[i] == ' ')
    {
        i++;
    }
    filename = &(in[i]);
}

//分割字符
void spilt(char in[], my_file* fp)
{
    fp->my_flag = 0;
    size_t j = 0;
    //把'<'和'>'的位置变成'\0',再把后面的文件名提取出来
    for(j=0;j<strlen(in);j++)
    {
       if(in[j] == '<')
       {
           fp->my_flag = O_RDONLY;
           in[j] = '\0';
           GetFileName(in,j+1);
           printf("%s\n",filename);
       }
       else if(in[j] == '>')
       {
          if(in[j+1] == '>')
          {
              fp->my_flag = O_WRONLY|O_CREAT|O_APPEND;
              GetFileName(in,j+2);
          }
          else
          {
              fp->my_flag = O_WRONLY|O_CREAT|O_TRUNC;
              GetFileName(in,j+1);
          }
          in[j] = '\0';
       } 
    }

    int i = 0;
    argv[i++] = strtok(in,SEP);//以' '分割字符
    while(argv[i++] = strtok(NULL, SEP));
}

int exeincmd()//执行内建命令
{
    if(strcmp(argv[0],"cd")==0)//如果是cd命令
    {
        //首先更改工作目录
        const char* target = argv[1];//目标路径
        if(target==NULL)    target = HOME();
        chdir(target);

        //获取工作目录，把工作目录放到环境变量
        char temp[1024];
        getcwd(temp,1024);
        //改变环境变量
        char pwd[1024];
        strcpy(pwd,"PWD=");
        strcat(pwd,temp);
        putenv(pwd);
        return 1;    
    }
    else if(strcmp(argv[0],"export")==0)//如果是导入环境变量
    {
        char env[1024];
        strcpy(env, argv[1]);
        putenv(env);
        return 1;
    }
    else if(strcmp(argv[0],"echo")==0)
    {
        if(argv[0]==NULL)
        {
            return 1;
        }
        else 
        {
            if(argv[1][0]=='$')//返回上一个命令的状态，0表示没有错误，其它任何值表明有错误
            {
                if(argv[1][1]=='?')
                {
                    printf("%d\n",exitcode);
                    exitcode = 0;
                    return 1;
                }
                else
                {
                    char* e = getenv(argv[1]+1);
                    printf("%s\n",e);
                    return 1;
                }
            }
            else//直接打印后面的内容
            {
                printf("%s\n",argv[1]);
                return 1;
            }
        }
    }
    return 0;
}



void execute(my_file* fp)
{
   pid_t id = fork();
   if(id==0)
   {
       //需要在子进程中进行重定向
    if(fp->my_flag&O_RDONLY)
    {
        int fd = open(filename,fp->my_flag);
        dup2(fd,0);
    }
    else if(fp->my_flag&O_WRONLY)
    {
        umask(0);
        int fd = open(filename,fp->my_flag,0666);
        dup2(fd,1);    
    }

     //子进程
    execvp(argv[0],argv);  
    exit(1);
   }
   int status = 0;
   pid_t rid = waitpid(id,&status,0);
   if(rid==id)  exitcode = WEXITSTATUS(status);
   //查看退出码
}
    


int main()
{
    
    while(1)
    {
        my_file f;
    
        //接受命令
        char commandline[size];
        int n = interactive(commandline);
        if(n==0)
            continue;
        
        //将字符分开
        spilt(commandline,&f);
       
        n = exeincmd();
        if(n)   continue;

        //执行命令
        execute(&f);

    }
    return 0;
}
